home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d18 / links.arc / LINKS.PAS next >
Pascal/Delphi Source File  |  1991-04-28  |  7KB  |  299 lines

  1. { Links Unit - Turbo Pascal 5.5
  2.   Patterned after the list processing facility in Simula class SIMSET.
  3.   Simula fans will note the same naming conventions as Simula-67.
  4.  
  5.   Written by Bill Zech @CIS:[73547,1034]), May 16, 1989.
  6.  
  7.   The Links unit defines objects and methods useful for implementing
  8.   list (set) membership in your own objects.
  9.  
  10.   Any object which inherits object <Link> will acquire the attributes
  11.   needed to maintain that object in a doubly-linked list.  Because the
  12.   Linkage object only has one set of forward and backward pointers, a
  13.   given object may belong to only one list at any given moment.  This
  14.   is sufficient for many purposes.  For example, a task control block
  15.   might belong in either a ready list, a suspended list, or a swapped
  16.   list, but all are mutually exclusive.
  17.  
  18.   A list is defined as a head node and zero or more objects linked
  19.   to the head node.  A head node with no other members is an empty
  20.   list.  Procedures and functions are provided to add members to the
  21.   end of the list, insert new members in position relative to an
  22.   existing member, determine the first member, last member, size
  23.   (cardinality) of the list, and to remove members from the list.
  24.  
  25.   Because your object inherits all these attributes, your program
  26.   need not concern itself with allocating or maintaining pointers
  27.   or other stuff.  All the actual linkage mechanisms will be
  28.   transparent to your object.
  29.  
  30.   *Note*
  31.       The following discussion assumes you have defined your objects
  32.       as static variables instead of pointers to objects.  For most
  33.       programs, dynamic objects manipulated with pointers will be
  34.       more useful.  Some methods require pointers as arguments.
  35.       Example program TLIST.PAS uses pointer type variables.
  36.  
  37.   Define your object as required, inheriting object Link:
  38.  
  39.         type
  40.             myObjType = object(Link)
  41.                 xxx.....xxxx
  42.             end;
  43.  
  44.   To establish a new list, declare a variable for the head node
  45.   as a type Head:
  46.  
  47.         var
  48.             Queue1    :Head;
  49.             Queue2    :Head;
  50.  
  51.     Define your object variables:
  52.  
  53.         var
  54.             X    : myObjType;
  55.             Y    : myObjType;
  56.             Z    : myObjType;
  57.             P    :^myObjType;
  58.  
  59.     Make sure the objects have been Init'ed as required for data
  60.     initialization, VMT setup, etc.
  61.  
  62.             Queue1.Init;
  63.             Queue2.Init;
  64.             X.Init;
  65.             Y.Init;
  66.             Z.Init;
  67.  
  68.     You can add your objects to a list with <Into>:
  69.     (Note the use of the @ operator to make QueueX a pointer to the
  70.      object.)
  71.  
  72.         begin
  73.             X.Into(@Queue1);
  74.             Y.Into(@Queue2);
  75.  
  76.     You can insert at a specific place with <Precede> or <Follow>:
  77.  
  78.             Z.Precede(@Y);
  79.             Z.Follow(@Y);
  80.  
  81.     Remove an object with <Out>:
  82.  
  83.             Y.Out;
  84.  
  85.     Then add it to another list:
  86.  
  87.             Y.Into(@Queue1);
  88.  
  89.     Note that <Into>, <Precede> and <Follow> all have a built-in
  90.     call to Out, so to move an object from one list to another can
  91.     be had with a single operation:
  92.  
  93.             Z.Into(@Queue1);
  94.  
  95.     You can determine the first and last elements with <First> and <Last>:
  96.     (Note the functions return pointers to objects.)
  97.  
  98.             P := Queue1.First;
  99.             P := Queue1.Last;
  100.  
  101.     The succcessor or predecessor of a given member can be found with
  102.     fucntions <Suc> and <Pred>:
  103.  
  104.             P := X.Pred;
  105.             P := Y.Suc;
  106.             P := P^.Suc;
  107.  
  108.     The number of elements in a list is found with <Cardinal>:
  109.  
  110.             N := Queue1.Cardinal;
  111.  
  112.     <Empty> returns TRUE is the list has no members:
  113.  
  114.             if Queue1.Empty then ...
  115.  
  116.     You can remove all members from a list with <Clear>:
  117.  
  118.             Queue1.Clear;
  119.  
  120.     GENERAL NOTES:
  121.  
  122.         The TP 5.5 type compatibility rules allow a pointer to a
  123.         descendant be assigned to an ancestor pointer, but not vice-versa.
  124.         So although it is perfectly legal to assign a pointer to
  125.         type myObjType to a pointer to type Linkage, it won't let
  126.         us do it the opposite.
  127.  
  128.         We would like to be able to assign returned values from
  129.         Suc, Pred, First, and Last to pointers of type myObjType,
  130.         and the least fussy way is to define these pointer types
  131.         internal to this unit as untyped pointers.  This works fine
  132.         because all we are really doing is passing around pointers
  133.         to Self, anyway.  The only down-side to this I have noticed
  134.         is you can't do:  P^.Suc^.Pred because the returned pointer
  135.         type cannot be dereferenced without a type cast.
  136. }
  137.  
  138. unit Links;
  139.  
  140. interface
  141.  
  142. type
  143.  
  144.   pLinkage = ^Linkage;
  145.   pLink = ^Link;
  146.   pHead = ^Head;
  147.  
  148.   Linkage = object
  149.       prede :pLinkage;
  150.       succ  :pLinkage;
  151.       function Suc  :pointer;
  152.       function Pred :pointer;
  153.       constructor Init;
  154.   end;
  155.  
  156.   Link = object(Linkage)
  157.       procedure Out;
  158.       procedure Into(s :pHead);
  159.       procedure Follow (x :pLinkage);
  160.       procedure Precede(x :pLinkage);
  161.   end;
  162.  
  163.   Head = object(Linkage)
  164.       function First :pointer;
  165.       function Last  :pointer;
  166.       function Empty :boolean;
  167.       function Cardinal :integer;
  168.       procedure Clear;
  169.       constructor Init;
  170.   end;
  171.  
  172.  
  173.  
  174. implementation
  175.  
  176. constructor Linkage.Init;
  177. begin
  178.   succ := NIL;
  179.   prede := NIL;
  180. end;
  181.  
  182. function Linkage.Suc :pointer;
  183. begin
  184.   if TypeOf(succ^) = TypeOf(Head) then
  185.      Suc := NIL
  186.   else Suc := succ;
  187. end;
  188.  
  189. function Linkage.Pred :pointer;
  190. begin
  191.   if TypeOf(prede^) = TypeOf(Head) then
  192.      Pred := NIL
  193.   else Pred := prede;
  194. end;
  195.  
  196. procedure Link.Out;
  197. begin
  198.     if succ <> NIL then
  199.     begin
  200.       succ^.prede := prede;
  201.       prede^.succ := succ;
  202.       succ := NIL;
  203.       prede := NIL;
  204.     end;
  205. end;
  206.  
  207. procedure Link.Follow(x :pLinkage);
  208. begin
  209.     Out;
  210.     if x <> NIL then
  211.     begin
  212.       if x^.succ <> NIL then
  213.       begin
  214.           prede := x;
  215.           succ := x^.succ;
  216.           x^.succ := @Self;
  217.           succ^.prede := @Self;
  218.       end;
  219.     end;
  220. end;
  221.  
  222.  
  223. procedure Link.Precede(x :pLinkage);
  224. begin
  225.     Out;
  226.     if x <> NIL then
  227.     begin
  228.         if x^.succ <> NIL then
  229.         begin
  230.             succ := x;
  231.             prede := x^.prede;
  232.             x^.prede := @Self;
  233.             prede^.succ := @Self;
  234.         end;
  235.     end;
  236. end;
  237.  
  238. procedure Link.Into(s :pHead);
  239. begin
  240.     Out;
  241.     if s <> NIL then
  242.     begin
  243.         succ := s;
  244.         prede := s^.prede;
  245.         s^.prede := @Self;
  246.         prede^.succ := @Self;
  247.     end;
  248. end;
  249.  
  250.  
  251. function Head.First :pointer;
  252. begin
  253.     First := suc;
  254. end;
  255.  
  256. function Head.Last :pointer;
  257. begin
  258.     Last := Pred;
  259. end;
  260.  
  261. function Head.Empty :boolean;
  262. begin
  263.   Empty := succ = prede;
  264. end;
  265.  
  266. function Head.Cardinal :integer;
  267. var
  268.     i   :integer;
  269.     p   :pLinkage;
  270. begin
  271.     i := 0;
  272.     p := succ;
  273.     while p <> @Self do
  274.       begin
  275.           i := i + 1;
  276.           p := p^.succ;
  277.       end;
  278.     Cardinal := i;
  279. end;
  280.  
  281. procedure Head.Clear;
  282. var
  283.     x  : pLink;
  284. begin
  285.     x := First;
  286.     while x <> NIL do
  287.       begin
  288.           x^.Out;
  289.           x := First;
  290.       end;
  291. end;
  292.  
  293. constructor Head.Init;
  294. begin
  295.   succ := @Self;
  296.   prede := @Self;
  297. end;
  298.  
  299. end.